package ye.guo.huang.fs.controller;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.Servlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.List;

/**
 * @Author: HUANG GY.
 * @Date: 2021/10/9 15:05
 * @Description: 文件上传
 */
@RestController
@RequestMapping("/api")
public class UploadController {

    private final static String UTF8 = "utf-8";

    /**
     *  分片
     * @param request
     * @param response
     * @return
     */
    @RequestMapping("/upload")
    public String upload(HttpServletRequest request, HttpServletResponse response){
        response.setCharacterEncoding(UTF8);
        Integer schunk = null ;
        Integer schunks = null ;
        String name = null ;
        String uploadPath = "D:\\05_code\\file-server\\fileItem" ;
        BufferedOutputStream os = null ;
        try {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            //缓冲区
            factory.setSizeThreshold(1024);
            //临时目录
            factory.setRepository(new File(uploadPath));
            ServletFileUpload upload = new ServletFileUpload(factory);
            //单个文件最大
            upload.setFileSizeMax(5L * 1024L * 1024L *1024L );
            //总体最大
            upload.setSizeMax(10L * 1024L * 1024L *1024L );

            List<FileItem> items = upload.parseRequest(request);
            for (FileItem item : items) {
                //表单域
                if (item.isFormField()) {
                    if ("chunk".equals(item.getFieldName())) {
                        schunk = Integer.parseInt(item.getString(UTF8));
                    }
                    if ("chunks".equals(item.getFieldName())) {
                        schunks = Integer.parseInt(item.getString(UTF8));
                    }
                    if ("name".equals(item.getFieldName())) {
                        name =  item.getString(UTF8);
                    }
                }
            }
            //写分片文件
            for (FileItem item : items) {
                //表单域
                if (!item.isFormField()) {
                    //临时文件名
                    String tempFileName = name ;
                    if (name!=null) {
                        if (schunk!=null) {
                            tempFileName = schunk + "_" + tempFileName ;
                        }
                        File tempFile = new File(uploadPath,tempFileName);
                        //断点续传：比如说网络中断重新上传
                        if (!tempFile.exists()) {
                            item.write(tempFile);
                        }
                    }
                }
            }
            //最后一个分片
            if (schunk != null && schunk.intValue() ==schunks.intValue() -1) {
                File file = new File(uploadPath,name);
                os = new BufferedOutputStream(new FileOutputStream(file));
                //文件合并
                for (int i = 0; i < schunks; i++) {
                    File tempFile = new File(uploadPath,i + "_" + name);
                    //嘴后一个分片上传后，进行文件合并，但是此时多线程情况下并不保证其它分片已经来了
                    int j = 0 ;
                    while (!tempFile.exists() && j < 100000) {
                        //文件不存在，进入循环
                        Thread.sleep(100);
                        //有的分配如果始终传不上来，这边不能始终进行阻塞
                        j++ ;
                    }
                    //读取这个分片
                    byte[] bytes = FileUtils.readFileToByteArray(tempFile);
                    os.write(bytes);
                    os.flush();
                    //删除临时文件
                    tempFile.delete();
                }
                os.flush();
            }

        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (os!=null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return "上传成功了"+name;
    }

    @RequestMapping("/down")
    public void downLoadFile(HttpServletRequest request, HttpServletResponse response){
        String uploadPath = "D:\\05_code\\file-server\\fileItem\\邵武市智慧体育公园智能健身步道项目原型图 - 需求说明.rar" ;
        File file = new File(uploadPath);
        response.setCharacterEncoding(UTF8);
        InputStream is = null ;
        OutputStream os = null ;
        try {
            //分片下载  http  Range bytes=100-1000
            long fSize = file.length();
            response.setContentType("application/x-download");
            //浏览器产生一个对话框，选择文件存放地址
            String fileName = URLEncoder.encode(file.getName(),UTF8);
            response.addHeader("Content-Disposition","attachment;filename="+fileName);
            //告诉前端是否支持分片下载
            response.setHeader("Accept-Range","bytes");
            response.setHeader("fSize",String.valueOf(fSize));
            response.setHeader("fName",fileName);

            long pos = 0 ,last = fSize-1,sum = 0 ;
            //判断前端是否需要分片下载
            if (null!=request.getHeader("Range")) {
                //206  分片下载的状态码
                response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
                //Range bytes=100-1000
                String numRange = request.getHeader("Range").replace("bytes=", "");
                String[] rangeArr = numRange.split("-");
                pos = Long.parseLong(rangeArr[0].trim());
                if (rangeArr.length == 2) {
                    last = Long.parseLong(rangeArr[1].trim());
                    last = last <= fSize -1 ? last : fSize -1 ;
                }else {
                    last = fSize - 1 ;
                }
            }
            //本次分片的大小
            long rangeLen = last - pos +1 ;
            //告诉客户端本次分片的信息
            String contentRange = new StringBuffer("bytes ")
                    .append(pos)
                    .append("-")
                    .append(last)
                    .append("/")
                    .append(fSize)
                    .toString();
            response.setHeader("Content-Range",contentRange);
            response.setHeader("Content-Length",String.valueOf(rangeLen));
            //初始化流 读文件
            os = new BufferedOutputStream(response.getOutputStream());
            is = new BufferedInputStream(new FileInputStream(file));
            //跳到pos的位置开始读
            is.skip(pos);
            byte[] buffer = new byte[1024];
            int length = 0 ;
            while (sum < rangeLen){
                length = is.read(buffer,0,(rangeLen-sum)<=buffer.length?(int)(rangeLen-sum):buffer.length);
                sum = sum + length ;
                os.write(buffer,0,length);
            }
            System.out.println("下载完成");
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if (is!=null) {
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (os!=null) {
                try {
                    os.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }


}